package com.ll19.webapp.filter;

import java.io.IOException;
import java.util.Locale;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.jstl.core.Config;

import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import com.ll19.Constants;

/**
 * Filter to wrap request with a request including user preferred locale.
 * 
 * OncePerRequestFilter顾名思义，他能够确保在一次请求只通过一次filter，而不需要重复执行。（即是说内部重定向将不过滤）
 * 
 * 在servlet-2.3中，Filter会过滤一切请求，包括服务器内部使用forward转发请求和<%@ include
 * file="/index.jsp"%>的情况。
 * 
 * 到了servlet-2.4中Filter默认下只拦截外部提交的请求，forward和include这些内部转发(就是内部重定向)都不会被过滤。
 * 
 * doFilterInternal 抽象方法 即执行 doFilter
 * 
 * 
 * 实现国际化除了Locale 还有 ResourceBundle
 * 
 * 
 */
public class LocaleFilter extends OncePerRequestFilter {

	/**
	 * This method looks for a "locale" request parameter. If it finds one, it
	 * sets it as the preferred locale and also configures it to work with JSTL.
	 * 
	 * @param request
	 *            the current request
	 * @param response
	 *            the current response
	 * @param chain
	 *            the chain
	 * @throws IOException
	 *             when something goes wrong
	 * @throws ServletException
	 *             when a communication failure happens
	 */
	@SuppressWarnings("unchecked")
	public void doFilterInternal(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {

		// Locale locale2 = request.getLocale();

		// 获取并设置本地标识
		String locale = request.getParameter("locale");

		// java.util.Locale 主要在软件的本地化时使用。它本身没有什么功能，更多的是作为一个参数辅助其他方法完成输出的本地化。
		// Locale myLocale = Locale.getDefault();
		// System.out.println(myLocale.getCountry());
		// System.out.println(myLocale.getLanguage());

		Locale preferredLocale = null;

		if (locale != null) {
			int indexOfUnderscore = locale.indexOf('_');
			if (indexOfUnderscore != -1) {
				String language = locale.substring(0, indexOfUnderscore);
				String country = locale.substring(indexOfUnderscore + 1);
				preferredLocale = new Locale(language, country);
			} else {
				preferredLocale = new Locale(locale);
			}
		}

		HttpSession session = request.getSession(false);

		if (session != null) {
			if (preferredLocale == null) {
				preferredLocale = (Locale) session
						.getAttribute(Constants.PREFERRED_LOCALE_KEY);
			} else {
				session.setAttribute(Constants.PREFERRED_LOCALE_KEY,
						preferredLocale);

				// 将用户登录选择的语言保持到session中，在filter里设置语言
				// Config.set(request, Config.FMT_LOCALE, 语言);
				// 页面用的是jstl
				// <fmt:message key="标签" bundle="${resources}"/>
				// 这样就可以完成动态的多语言选择

				// <fmt:setLocale>可以為你設置地區資訊，如果你想使用程式碼來設置地區資訊，則可以使用Config的set()如下設定

				// Config.set(pageContext, Config.FMT_LOCALE, new Locale("ja",
				// "JP"), PageContext.PAGE_SCOPE);

				// 例如中国大陆为zh_CN，美国为en_US。假如资源名称为message，则默认的资源文件为message.properties，中国大陆资源文
				// 件为message_zh_CN.properties，美国资源文件为message_en_US.properties。

				// 在java se中是 尝试使用 Locale.getDefault()获取国际化信息 之后根据上述说明 获取对应的资源文件

				// 在JSTL中则略有不同，简单地说，JSTL的i18n相容性标签，
				// 会尝试从属性范围中取得javax.servlet.jsp.jstl.fmt.LocalizationContext物件，藉以决定资源包与地区资讯，具体来说，决定讯息档案的顺序如下：
				
				// 使用指定的Locale物件取得讯息档案 即Config.set 或者 <fmt:setLocale>
				// 根据浏览器Accept-Language标头指定的偏好地区（Prefered
				// locale）顺序，这可以使用HttpServletRequest的getLocales()来取得
				// 根据后备地区（fallback locale）资讯取得讯息档案 应该是本地locale.getDetault()
				// 使用基础名称取得讯息档案 即默认的资源文件

				// 一个支持多个Locale的系统通常有多个资源文件。例如，如果某Locale对应的properties文件存在，则会优先显示该properties文件里的内容。

				// 如果该properties文件不存在，或者文件存在但是该key-value属性对不存在，则会显示默认显示资源文件里的内容。

				// JSTL的FMT标签对应的默认前缀配置在web.xml中
				// <!-- 国际化文件的前缀名-->
				// <context-param>
				// <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
				// <param-value>ApplicationResources</param-value>
				// </context-param>
				// 则默认会读取ApplicationResources.properties的配置文件

				Config.set(session, Config.FMT_LOCALE, preferredLocale);
			}

			if (preferredLocale != null
					&& !(request instanceof LocaleRequestWrapper)) {
				request = new LocaleRequestWrapper(request, preferredLocale);
				// 绑定线程
				LocaleContextHolder.setLocale(preferredLocale);
			}
		}

		chain.doFilter(request, response);

		// chain.doFilter()之后，置空线程中的LocaleContext
		LocaleContextHolder.setLocaleContext(null);
	}
}
